Support VCPU migration for VMX guests.
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 11 Aug 2005 21:38:58 +0000 (21:38 +0000)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 11 Aug 2005 21:38:58 +0000 (21:38 +0000)
Add a hook to support CPU migration for VMX domains

Reorganize the low level asm code to support relaunching a VMCS on a different
logical CPU.

Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Signed-off-by: Arun Sharma <arun.sharma@intel.com>
xen/arch/ia64/domain.c
xen/arch/x86/domain.c
xen/arch/x86/vmx_vmcs.c
xen/arch/x86/x86_32/entry.S
xen/arch/x86/x86_64/entry.S
xen/common/dom0_ops.c
xen/include/asm-x86/vmx.h
xen/include/asm-x86/vmx_vmcs.h
xen/include/xen/domain.h

index f57a5699ab0a611aed72322bce815c1e813448f1..bceacd300c339738c5de8f3157ff52e20250aa34 100644 (file)
@@ -1398,3 +1398,12 @@ void domain_pend_keyboard_interrupt(int irq)
 {
        vcpu_pend_interrupt(dom0->vcpu[0],irq);
 }
+
+void vcpu_migrate_cpu(struct vcpu *v, int newcpu)
+{
+       if ( v->processor == newcpu )
+               return;
+
+       set_bit(_VCPUF_cpu_migrated, &v->vcpu_flags);
+       v->processor = newcpu;
+}
index efd967464d1ca337b4fb4fafd98555a93f29834d..598c2095eede2fdc2d3591241cd6e98d54425d0c 100644 (file)
@@ -295,27 +295,24 @@ void arch_do_boot_vcpu(struct vcpu *v)
         l1e_from_page(virt_to_page(gdt_table), PAGE_HYPERVISOR);
 }
 
-#ifdef CONFIG_VMX
-static int vmx_switch_on;
-
-void arch_vmx_do_resume(struct vcpu *v) 
+void vcpu_migrate_cpu(struct vcpu *v, int newcpu)
 {
-    u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs);
-
-    load_vmcs(&v->arch.arch_vmx, vmcs_phys_ptr);
-    vmx_do_resume(v);
-    reset_stack_and_jump(vmx_asm_do_resume);
-}
+    if ( v->processor == newcpu )
+        return;
 
-void arch_vmx_do_launch(struct vcpu *v) 
-{
-    u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs);
+    set_bit(_VCPUF_cpu_migrated, &v->vcpu_flags);
+    v->processor = newcpu;
 
-    load_vmcs(&v->arch.arch_vmx, vmcs_phys_ptr);
-    vmx_do_launch(v);
-    reset_stack_and_jump(vmx_asm_do_launch);
+    if ( VMX_DOMAIN(v) )
+    {
+        __vmpclear(virt_to_phys(v->arch.arch_vmx.vmcs));
+        v->arch.schedule_tail = arch_vmx_do_relaunch;
+    }
 }
 
+#ifdef CONFIG_VMX
+static int vmx_switch_on;
+
 static int vmx_final_setup_guest(
     struct vcpu *v, struct vcpu_guest_context *ctxt)
 {
@@ -346,7 +343,7 @@ static int vmx_final_setup_guest(
 
     v->arch.schedule_tail = arch_vmx_do_launch;
 
-#if defined (__i386)
+#if defined (__i386__)
     v->domain->arch.vmx_platform.real_mode_data = 
         (unsigned long *) regs->esi;
 #endif
index dd2f11c4a024c53671a27283e9eae37129ae507a..c83df67ddffb72c1480abd57863b6d46850975f5 100644 (file)
@@ -198,7 +198,7 @@ void vmx_set_host_env(struct vcpu *v)
     host_env.idtr_limit = desc.size;
     host_env.idtr_base = desc.address;
     error |= __vmwrite(HOST_IDTR_BASE, host_env.idtr_base);
+
     __asm__ __volatile__ ("sgdt  (%0) \n" :: "a"(&desc) : "memory");
     host_env.gdtr_limit = desc.size;
     host_env.gdtr_base = desc.address;
@@ -210,7 +210,6 @@ void vmx_set_host_env(struct vcpu *v)
     host_env.tr_base = (unsigned long) &init_tss[cpu];
     error |= __vmwrite(HOST_TR_SELECTOR, host_env.tr_selector);
     error |= __vmwrite(HOST_TR_BASE, host_env.tr_base);
-
 }
 
 void vmx_do_launch(struct vcpu *v) 
@@ -544,6 +543,36 @@ void vm_resume_fail(unsigned long eflags)
     __vmx_bug(guest_cpu_user_regs());
 }
 
+void arch_vmx_do_resume(struct vcpu *v) 
+{
+    u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs);
+
+    load_vmcs(&v->arch.arch_vmx, vmcs_phys_ptr);
+    vmx_do_resume(v);
+    reset_stack_and_jump(vmx_asm_do_resume);
+}
+
+void arch_vmx_do_launch(struct vcpu *v) 
+{
+    u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs);
+
+    load_vmcs(&v->arch.arch_vmx, vmcs_phys_ptr);
+    vmx_do_launch(v);
+    reset_stack_and_jump(vmx_asm_do_launch);
+}
+
+void arch_vmx_do_relaunch(struct vcpu *v)
+{
+    u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs);
+
+    load_vmcs(&v->arch.arch_vmx, vmcs_phys_ptr);
+    vmx_do_resume(v);
+    vmx_set_host_env(v);
+    v->arch.schedule_tail = arch_vmx_do_resume;
+
+    reset_stack_and_jump(vmx_asm_do_relaunch);
+}
+
 #endif /* CONFIG_VMX */
 
 /*
index 99d5b1fbc28bb2397f6102afd3030a797d2e6a28..a2491612d76152a9089d00aa5cb68abbdfcc7a2c 100644 (file)
         pushl %ecx; \
         pushl %ebx;
 
+#define VMX_RESTORE_ALL_NOSEGREGS   \
+        popl %ebx;  \
+        popl %ecx;  \
+        popl %edx;  \
+        popl %esi;  \
+        popl %edi;  \
+        popl %ebp;  \
+        popl %eax;  \
+        addl $(NR_SKIPPED_REGS*4), %esp
+
 ENTRY(vmx_asm_vmexit_handler)
         /* selectors are restored/saved by VMX */
         VMX_SAVE_ALL_NOSEGREGS
         call vmx_vmexit_handler
         jmp vmx_asm_do_resume
 
-ENTRY(vmx_asm_do_launch)
-        popl %ebx
-        popl %ecx
-        popl %edx
-        popl %esi
-        popl %edi
-        popl %ebp
-        popl %eax
-        addl $(NR_SKIPPED_REGS*4), %esp
-        /* VMLUANCH */
-        .byte 0x0f,0x01,0xc2
-        pushf
-        call vm_launch_fail
-        hlt
-        
-        ALIGN
-        
-ENTRY(vmx_asm_do_resume)
-vmx_test_all_events:
+.macro vmx_asm_common launch initialized
+1:
+/* vmx_test_all_events */
+        .if \initialized
         GET_CURRENT(%ebx)
 /*test_all_events:*/
         xorl %ecx,%ecx
@@ -142,34 +137,50 @@ vmx_test_all_events:
         movl VCPU_processor(%ebx),%eax
         shl  $IRQSTAT_shift,%eax
         test %ecx,irq_stat(%eax,1)
-        jnz  vmx_process_softirqs
+        jnz 2f
 
-vmx_restore_all_guest:
+/* vmx_restore_all_guest */
         call load_cr2
+        .endif
+        VMX_RESTORE_ALL_NOSEGREGS
         /* 
          * Check if we are going back to VMX-based VM
          * By this time, all the setups in the VMCS must be complete.
          */
-        popl %ebx
-        popl %ecx
-        popl %edx
-        popl %esi
-        popl %edi
-        popl %ebp
-        popl %eax
-        addl $(NR_SKIPPED_REGS*4), %esp
+        .if \launch
+        /* VMLUANCH */
+        .byte 0x0f,0x01,0xc2
+        pushf
+        call vm_launch_fail
+        .else
         /* VMRESUME */
         .byte 0x0f,0x01,0xc3
         pushf
         call vm_resume_fail
+        .endif
         /* Should never reach here */
         hlt
 
         ALIGN
-vmx_process_softirqs:
+        .if \initialized
+2:
+/* vmx_process_softirqs */
         sti       
         call do_softirq
-        jmp  vmx_test_all_events
+        jmp 1b
+        ALIGN
+        .endif
+.endm
+
+ENTRY(vmx_asm_do_launch)
+    vmx_asm_common 1 0
+
+ENTRY(vmx_asm_do_resume)
+    vmx_asm_common 0 1
+
+ENTRY(vmx_asm_do_relaunch)
+    vmx_asm_common 1 1
+
 #endif
 
         ALIGN
index a8a5574e2c86d12ef4d620ee0f8a629ff33b71c8..0f24b15ca12b4b1ce2e326992b531787770eb687 100644 (file)
@@ -194,39 +194,34 @@ test_all_events:
         pushq %r14; \
         pushq %r15; \
 
+#define VMX_RESTORE_ALL_NOSEGREGS \
+        popq %r15; \
+        popq %r14; \
+        popq %r13; \
+        popq %r12; \
+        popq %rbp; \
+        popq %rbx; \
+        popq %r11; \
+        popq %r10; \
+        popq %r9;  \
+        popq %r8;  \
+        popq %rax; \
+        popq %rcx; \
+        popq %rdx; \
+        popq %rsi; \
+        popq %rdi; \
+        addq $(NR_SKIPPED_REGS*8), %rsp; \
+
 ENTRY(vmx_asm_vmexit_handler)
         /* selectors are restored/saved by VMX */
         VMX_SAVE_ALL_NOSEGREGS
         call vmx_vmexit_handler
         jmp vmx_asm_do_resume
 
-ENTRY(vmx_asm_do_launch)
-        popq %r15
-        popq %r14
-        popq %r13
-        popq %r12
-        popq %rbp
-        popq %rbx
-        popq %r11
-        popq %r10
-        popq %r9
-        popq %r8
-        popq %rax
-        popq %rcx
-        popq %rdx
-        popq %rsi
-        popq %rdi
-        addq $(NR_SKIPPED_REGS*8), %rsp
-        /* VMLUANCH */
-        .byte 0x0f,0x01,0xc2
-        pushfq
-        call vm_launch_fail
-        hlt
-        
-        ALIGN
-        
-ENTRY(vmx_asm_do_resume)
-vmx_test_all_events:
+.macro vmx_asm_common launch initialized 
+1:
+        .if \initialized
+/* vmx_test_all_events */
         GET_CURRENT(%rbx)
 /* test_all_events: */
         cli                             # tests must not race interrupts
@@ -235,42 +230,51 @@ vmx_test_all_events:
         shl   $IRQSTAT_shift,%rax
         leaq  irq_stat(%rip), %rdx
         testl $~0,(%rdx,%rax,1)
-        jnz   vmx_process_softirqs
+        jnz  2f 
 
-vmx_restore_all_guest:
+/* vmx_restore_all_guest */
         call load_cr2
+        .endif
         /* 
          * Check if we are going back to VMX-based VM
          * By this time, all the setups in the VMCS must be complete.
          */
-        popq %r15
-        popq %r14
-        popq %r13
-        popq %r12
-        popq %rbp
-        popq %rbx
-        popq %r11
-        popq %r10
-        popq %r9
-        popq %r8
-        popq %rax
-        popq %rcx
-        popq %rdx
-        popq %rsi
-        popq %rdi
-        addq $(NR_SKIPPED_REGS*8), %rsp
+        VMX_RESTORE_ALL_NOSEGREGS
+        .if \launch
+        /* VMLUANCH */
+        .byte 0x0f,0x01,0xc2
+        pushfq
+        call vm_launch_fail
+        .else
         /* VMRESUME */
         .byte 0x0f,0x01,0xc3
         pushfq
         call vm_resume_fail
+        .endif
         /* Should never reach here */
         hlt
 
         ALIGN
-vmx_process_softirqs:
+
+        .if \initialized
+2:
+/* vmx_process_softirqs */
         sti       
         call do_softirq
-        jmp  vmx_test_all_events
+        jmp 1b
+        ALIGN
+        .endif
+.endm
+
+ENTRY(vmx_asm_do_launch)
+      vmx_asm_common 1 0
+
+ENTRY(vmx_asm_do_resume)
+      vmx_asm_common 0 1
+
+ENTRY(vmx_asm_do_relaunch)
+      vmx_asm_common 1 1
+
 #endif
 
         ALIGN
index d189528df2a71804ab33c630e77f507c9edb045f..9964714d03740e42ab6e20746528bcf5fdf51b92 100644 (file)
@@ -293,17 +293,17 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
         v->cpumap = cpumap;
 
         if ( cpumap == CPUMAP_RUNANYWHERE )
+        {
             clear_bit(_VCPUF_cpu_pinned, &v->vcpu_flags);
+        }
         else
         {
             /* pick a new cpu from the usable map */
             int new_cpu = (int)find_first_set_bit(cpumap) % num_online_cpus();
 
             vcpu_pause(v);
-            if ( v->processor != new_cpu )
-                set_bit(_VCPUF_cpu_migrated, &v->vcpu_flags);
+            vcpu_migrate_cpu(v, new_cpu);
             set_bit(_VCPUF_cpu_pinned, &v->vcpu_flags);
-            v->processor = new_cpu;
             vcpu_unpause(v);
         }
 
index 5596549ce1b85199d79d14351b26eadb0b7e1100..714969eb2e8db5190796e3286478286d975280d9 100644 (file)
@@ -35,6 +35,7 @@ extern void vmx_intr_assist(struct vcpu *d);
 
 extern void arch_vmx_do_launch(struct vcpu *);
 extern void arch_vmx_do_resume(struct vcpu *);
+extern void arch_vmx_do_relaunch(struct vcpu *);
 
 extern int vmcs_size;
 extern unsigned int cpu_rev;
index 68db612665190e98ab2623f30ea02e93dd27bc73..987e4e79e6274d4c50114d9ffde8ddc948eccc5c 100644 (file)
@@ -93,6 +93,7 @@ struct arch_vmx_struct {
 
 void vmx_do_launch(struct vcpu *); 
 void vmx_do_resume(struct vcpu *); 
+void vmx_set_host_env(struct vcpu *);
 
 struct vmcs_struct *alloc_vmcs(void);
 void free_vmcs(struct vmcs_struct *);
index 46c2e4bb5d7a898561cd8074d895f0eb9d33a2b0..cf3a1922600f4b52bf7f0d599edd544223ae7949 100644 (file)
@@ -15,7 +15,9 @@ extern void arch_do_createdomain(struct vcpu *v);
 extern void arch_do_boot_vcpu(struct vcpu *v);
 
 extern int  arch_set_info_guest(
-    struct vcpu *d, struct vcpu_guest_context *c);
+    struct vcpu *v, struct vcpu_guest_context *c);
+
+extern void vcpu_migrate_cpu(struct vcpu *v, int newcpu);
 
 extern void free_perdomain_pt(struct domain *d);